home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / FC2P2SRC.ZIP / TUNNEL.DOC < prev   
Text File  |  1995-09-05  |  9KB  |  239 lines

  1.                      How to do free-directional tunnels
  2.                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  3.                           by BlackAxe / KoLOr 1997
  4.  
  5.  
  6. In the latest demos (in almost every demo from Assembly97) you see those
  7. funny free-directional tunnels, namely tunnels where you can move how you
  8. want and perform complex camera movements.
  9. Many people in iRC asked me how to do such a tunnel, so instead of wasting
  10. phone costs and explaining it online i decided to write this little tute.
  11. In fact, this effect is kinda easy to do, but unlike normal, old, silly 
  12. tubes it doesn't work with those silly lookup tables (darn, I hate lookup
  13. tables :-)), but in fact it's realtime raytraycing. Realtime Raytraycing??
  14. Isn't that slow? No, there are some tricks to make it possible in realtime.
  15. Well, let's start with a little introduction to raytraycing.
  16.  
  17. 1.) Raytraycing, the basics
  18. ~~~~~~~~~~~~~~~~~~~~~~~~~~~
  19. In fact, raytraycing is a very easy algorithm, many people think it's hard
  20. as hell, because one get's good quality pictures out of it, but the basics
  21. are easy. Performing refractions, reflections and other complex things is a
  22. bit more advanced, but the basics are very very easy, everyone that knows a
  23. bit math should understand it.
  24. Well, basically the algorithm consists of shooting a ray through each pixel
  25. of the screen and check for intersections of this ray with objects in the 
  26. scene. Let's start with the equation of a ray. A ray is defined as
  27.  
  28.         Origin + t*Direction
  29. where Origin is the vector of the camera, and Direction a normalized direction
  30. vector. t is a float that indicates a position on the ray. Now for shooting
  31. a ray through a pixel, we do the following, if we consider the camera to be
  32. at (0,0,-256)
  33.         Origin.x = 0;
  34.         Origin.y = 0;
  35.         Origin.z = -128;
  36.  
  37. now we shoot the ray through that pixel:
  38.         Direction.x = Pixel.X;
  39.         Direction.y = Pixel.Y;
  40.         Direction.z = 128;
  41.         Direction.Normalize();
  42. of course you can take something different for Z, that's your decision.
  43. Note: The midmost pixel of the screen muts be (0,0), so if you work in 
  44. 320x200 you first have to substract 160 of X and 100 of Y (or 320 resp. 240
  45. when you work in 640x480). And don't forget to normalize the Direction
  46. (if you don't know how to normalize a vector, first check a vector tutorial
  47. like ZED3D), hmm, well, here's the little function to normalize a vector for
  48. all you dummies :-))
  49.  
  50. void Vector::Normalize()
  51. {
  52.   float len = sqrt(x*x + y*y + z*z);
  53.   x /= len;
  54.   y /= len;
  55.   z /= len;
  56. }
  57.  
  58. Now you have your ray, and you need to check for intersections. For that, you
  59. need to find t (of course, because you know the rest :-)). Then you have
  60.         Intersection = Origin + t*Direction
  61. how funny :-)
  62. [Intersection is a vector ofcourse]
  63.  
  64.  
  65.  
  66. 2.) Doing the raytraycing for the tunnel
  67. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  68. Think! What is a tunnel?? A tunnel is a cylinder, a simply silly cylinder.
  69. And what is a cylinder??? A cylinder is a set of circles on a straight line.
  70. Each Z coordinate has a circle. So it's just circles for each Z :-)
  71. Now we have to find the intersection between our ray and the correct circle.
  72. Recall the equation of a circle from your math course:
  73.  
  74.         (x-a)^2 + (y-b)^2 = r^2
  75. (a,b) is the center of the circle, and r is the radius. As we suppose the
  76. circles are on (0,0) this becomes
  77.         x^2 + y^2 = r^2
  78. easy huu :-)
  79.  
  80. Now we substitute the ray equation in this equation.
  81.         (Origin.x + t*Direction.x)^2 + (Origin.y + t*Direction.y)^2 = r^2
  82. and we calculate this out
  83.  
  84. Origin.x^2 + 2*Origin.x*t*Direction.x + t^2*Direction.x^2 +
  85.   Origin.y^2 + 2*Origin.y*t*Direction.y + t^2*Direction.y^2 = r^2
  86.  
  87. now we group all terms that should be grouped :-)
  88. t^2*(Direction.x^2 + Direction.y^2) + t*2*(Origin.x*Direction.x + 
  89.   Origin.y*Direction.y) + Origin.x^2 + Origin.y^2 - r^2 = 0;
  90. ain't this a nice quadratic equation? Hmm, let's write it like this
  91.  
  92. a*t^2 + b*t + c = 0
  93.  
  94. where:
  95.   a = Direction.x^2 + Direction.y^2
  96.   b = 2*(Origin.x*Direction.x + Origin.y*Direction.y)
  97.   c = Origin.x^2 + Origin.y^2 - r^2
  98.  
  99. Now we need to solve this equation. From your math course you should now how
  100. to solve quadratic equations:
  101. we first have to calculate the discriminent delta
  102.         delta = b^2 - 4*a*c
  103.  
  104. Now if delta < 0, there are no real solutions, only complex ones, if this
  105.   case happens, there's no Intersection and we can draw a background colour.
  106. If delta = 0, there's ONE intersection, that is calculated as follows
  107.              -b
  108.         t = -----
  109.              2*a
  110.  
  111. If delta > 0, there are TWO real intersections:
  112.  
  113.              -b - sqrt(delta)
  114.         t1 = ----------------
  115.                   2*a
  116.  
  117.              -b + sqrt(delta)
  118.         t2 = ----------------
  119.                   2*a
  120.  
  121. We are only interested in the nearer of those intersections, so we do
  122.         t = min(t1, t2);
  123.  
  124. Now you have your intersection between the ray and the cylinder :-)
  125. Intersection = Origin + t*Direction
  126.  
  127. One thing rests: we need to texturemap the tunnel. This is easy to, we just
  128. apply cylindric mapping to the Intersection point.
  129.  
  130. we just do:
  131.  
  132. u = abs(Intersection.z)*0.2;
  133. v = abs(atan2(Intersection.y, Intersection.x)*256/PI);
  134.  
  135. that's it :-) you can combine that with depth cue too, i.e. taking the Z into 
  136. account to get a shade-level, but i leave that to you.
  137. That's already it. If you do that for each pixel, you get a nice tunnel :-)
  138.  
  139.  
  140. 3.) Moving the camera
  141. ~~~~~~~~~~~~~~~~~~~~~
  142. You want to move your camera ofcourse :-)
  143. That's easy, change your Origin vector's x,y of you want to move your camera,
  144. and if you want to to rotate, just rotate your Direction vector using a matrix
  145. or normal 12 mul rotation. I won't go any further into this, as it's really
  146. basic stuff, see the source below to check how it works.
  147.  
  148.  
  149. 4.) Doing it in realtime
  150. ~~~~~~~~~~~~~~~~~~~~~~~~
  151. I hear you cry, this is IMPOSSIBLE in realtime. Well in fact it is, tracing
  152. rays for each pixel :-) But you won't do that, won't you. In fact you just trace
  153. rays for some pixel and interpolate between. I take a 40x25 grid (that is 8x8
  154. pixels large) shoot a ray for each grid, i.e. getting (u,v) for each grid 
  155. position, and interpolate between, that way i get a full 320x200 screen by only
  156. calculating 1000 intersections, and it's precise enough. That method can be used
  157. for other 2d effects too, kinda great for bitmap distortions.
  158.  
  159.  
  160. 5.) Some example source for the lazy ones
  161. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  162. u,v are an index to a 256x256 texturemap, and as Radius I take 256
  163.  
  164. virtual void FreeTunnel::GetUV(int x,int y, int &u, int &v)
  165. {
  166.   Vector Direction(x-160, y-100, 256);
  167.   Direction *= RotationMatrix;
  168.   Direction.Normalize();        // normalize Direction vector
  169.  
  170.   Vector Origin(100, 100, -256);
  171.  
  172.  
  173.   // calculate the stuff :-)
  174.   float a = fsqr(Direction.x) + fsqr(Direction.y);
  175.   float b = 2*(Origin.x*Direction.x + Origin.y*Direction.y);
  176.   float c = fsqr(Origin.x) + fsqr(Origin.y) - fsqr(Radius);
  177.  
  178.   // calculate discriminent delta
  179.   float delta = fsqr(b) - 4*a*c;
  180.  
  181.   // if there's no real solution
  182.   if (delta < 0)
  183.     {
  184.       u = 128;
  185.       v = 128;
  186.       return;
  187.     }
  188.  
  189.   float t,t1,t2;
  190.   // there are 2 solutions, get the nearest ... this case should never happen
  191.   t1 = (-b + sqrt(delta))/(2*a);
  192.   t2 = (-b - sqrt(delta))/(2*a);
  193.   t = min(t1, t2);                      // min here
  194.  
  195.   // finnally the intersection
  196.   Vector Intersection = Origin + t*Direction;
  197.  
  198. // do the mapping
  199.   u = (int)(fabs(Intersection.z)*0.2);
  200.   v = (int)(fabs(atan2(Intersection.y, Intersection.x)*256/PI));
  201.  
  202.  
  203. Again, i call that for 40x25 and interpolate between the (u,v) set.
  204. As you can see, i used OOP massively, e.g for Vectors and Matrices.
  205. OOP really helps you alot, you should try it.
  206. If you take an 80x50 grid (4x4 interpolation) you might get better results, but
  207. this works fine for me.
  208.  
  209. That's pretty much it, now go ahead and code yourself a killer-tunnel.
  210. If you want to see this tunnel in action, get our Evoke97 demo (1st place)
  211. the archive is called KWISSEN.ZIP and you should find it on cdrom.com.
  212.  
  213.  
  214. 6.) Greets
  215. ~~~~~~~~~~
  216. Greets fly to (no order):
  217. Tomh, Climax, Shiva, Fontex, Raytrayza, Noize, LordChaos, Red13, kb, DrYes, 
  218. Siriuz, Crest, Gaffer, Trickster, Houlq, Screamager, LoneWolf, Magic, Unreal,
  219. Aap, Cirion, Kyp, Assign, and the rest i have forgotten in some way.
  220.  
  221. If you feel the need to contact me, do so :-)
  222. In the moment i don't have any e-mail, but i'll get one soon. Try to catch me
  223. on iRC (channel #coders and #coders.ger on IRCNET and #luxusbuerg on UnderNet)
  224. Or snail-mail me
  225.     Laurent Schmalen
  226.     6, rue Tony Schmit
  227.     L-9081 Ettelbruck
  228.     G.D. Luxembourg
  229.  
  230. have fun and stay trippy dudes!
  231.  
  232.     
  233.  
  234.  
  235.  
  236.  
  237.  
  238.